import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import java.util.Date;




public class Aggregate {
	
	List<CrawlResult> results;
	long timeRan;
	PrintWriter out;
	
	public Aggregate(String mode, List<CrawlResult> r, long time, Date startDate, Date endDate) {
		
		results = r;
		timeRan = time;
		
		try {
			out = new PrintWriter(new BufferedWriter(new FileWriter("results.html")));
		} catch (Exception e) {
			System.err.println("PrintWriter Error: ");
			e.printStackTrace();
		}
		
		out.println("<html>");
		out.println("Start Date: " + startDate.toString());
		out.println("<br>End Date: " + endDate.toString());
		out.println("<br>Time Ran: " + time + " seconds");
		out.println("<body>");
		if (mode == "full") {
			printNumberofNodesdiscovered();
			printAvgMinMaxNumFiles();
			printAvgMinMaxFileSizes();
			printTop10Ext();
			printFullData();
		}
		else {
			printNumberofNodesdiscovered();
			printMinimalData();
		}
		out.println("</body>");
		out.println("</html>");
		out.close();
	}
	
	public void printMinimalData() {
		out.println();
		out.println("<h2>Minimal Data:<h2>");
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println();
		out.println(
				"<tr>" +
				"<th>Host:Port</th>" +
				"<th>Agent</th>" +
				"<th>Status</th>" +
				"</tr>");
		Boolean blue = true;
		for (int i=0;i<results.size();i++){
			if(blue == true) 
				out.println("<tr bgcolor=#A9D0F5>");
			else
				out.println("<tr bgcolor=white>");
			out.println("<td>" + results.get(i).getHostPort() + "</td>" +
						"<td>" + results.get(i).getAgent()    + "</td>" + 
						"<td>" + results.get(i).getStatus()   + "</td>" );
			out.println("</tr>");
			blue = !blue;
		}
		out.println("</table><br>");
	}
	
	public void printFullData() {
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println();
		out.println("<h2>Full Data:</h2>");
		out.println();
		out.println(
				"<tr>" +
				"<th>Host:Port</th>" +
				"<th>Agent</th>" +
				"<th>Status</th>" +
				"<th>Number of Files</th>" +
				"<th>File</th>" +
				"</tr>");
		Boolean blue=true;
		for (int i=0;i<results.size();i++){
			blue = !blue;
			if(blue == true) 
				out.println("<tr bgcolor=#A9D0F5>");
			else
				out.println("<tr bgcolor=white>");
			out.println(
							"<td>" + results.get(i).getHostPort() + "</td>" +
							"<td>" + results.get(i).getAgent()    + "</td>" + 
							"<td>" + results.get(i).getStatus()   + "</td>" + 
							"<td>" + results.get(i).getFilesListSize().size() + "</td>" + 
							"<td>" +
								"<form>" + 
									"<table>" +
										"<tr>" );
//			for(int j=0; j<results.get(i).getFilesList().size(); j++) {
//				out.println("<td>" + results.get(i).getFilesList().get(j) + "</td>");
//			}
			out.println("</tr><tr>");
			for(int j=0; j<results.get(i).getFilesListExt().size(); j++) {
				out.println("<td>" + results.get(i).getFilesListExt().get(j) + "</td>");
			}
			out.println("</tr><tr>");
			for(int j=0; j<results.get(i).getFilesListSize().size(); j++) {
				out.println("<td>" + results.get(i).getFilesListSize().get(j) + "</td>");
			}
			out.println(
										"</tr>" +
									"</table>" +
								"</form>" +
							"</td>" +				
						"</tr>");
						
		}
		out.println("</table><br>");
	}	
	
	//probably more efficient to be able to read of the size of the queue
	public void printNumberofNodesdiscovered(){
		int crawledSuccesfully = 0;
		int otherexception = 0;
		int timeout = 0;
		int notCrawled = 0;	
		ArrayList<String> allNodes = new ArrayList<String>();
		
		
		for(int i=0; i < results.size();i++){
			if ( allNodes.contains(results.get(i).getHostPort()) == false )
    			allNodes.add(results.get(i).getHostPort());
			
			// Add unique leaves
			String leaveResult = results.get(i).getLeaves();
			if(!leaveResult.isEmpty()) {
				String[] leaveNodes = {leaveResult};
				if( leaveResult.contains(",") ) {
		        	leaveNodes = leaveResult.split(",");
				}
	        	for(int j=0; j<leaveNodes.length; j++) {
	        		if ( allNodes.contains(leaveNodes[j]) == false )
	        			allNodes.add(leaveNodes[j]);
	        	}
	        }
			
			// Add unique ultrapeers
			String ultraResult = results.get(i).getUltrapeers();
			if(!ultraResult.isEmpty()) {
				String[] ultraNodes = {ultraResult};
				if( ultraResult.contains(",") ) {
		        	ultraNodes = ultraResult.split(",");
				}
	        	for(int j=0; j<ultraNodes.length; j++) {
	        		if ( allNodes.contains(ultraNodes[j]) == false )
	        			allNodes.add(ultraNodes[j]);
	        	}
	        }
			
			// Count number of nodes for each status
			if (results.get(i).getStatus().contains("Node Successfully Crawled")==true){
				crawledSuccesfully++;
			}else if (results.get(i).getStatus().contains("Timeout Exception")==true){
				timeout++;
			}else{
				otherexception++;
			}
			
		}
		notCrawled = allNodes.size() - results.size();
		
		// Print Results
		out.println("<h2>Statistics</h2>");
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println("<tr> <th>Node Status</th> <th>Count</th> <th>Discovery Rate</th> </tr>");
		out.println("<tr> <td>Discovered:</td> <td>"                       + allNodes.size()    + "</td> <td>" + (float)allNodes.size()/timeRan    + "</td> </tr>");
		out.println("<tr> <td>Crawled:</td> <td>"                          + results.size()     + "</td> <td>" + (float)results.size()/timeRan     + "</td> </tr>");
		out.println("<tr> <td>Not Crawled:</td> <td>"                      + notCrawled         + "</td> <td>" + (float)notCrawled/timeRan         + "</td> </tr>");
		out.println("<tr> <td>Crawled Failed - Timeout:</td> <td>"         + timeout            + "</td> <td>" + (float)timeout/timeRan            + "</td> </tr>");
		out.println("<tr> <td>Crawled Failed - Other Exception:</td> <td>" + otherexception     + "</td> <td>" + (float)otherexception/timeRan     + "</td> </tr>");		
		out.println("<tr> <td>Crawled Succesfully:</td> <td>"              + crawledSuccesfully + "</td> <td>" + (float)crawledSuccesfully/timeRan + "</td> </tr>");
		out.println("</table>");
	}
	
	public void printAvgMinMaxNumFiles() {
		int maxNumFiles = results.get(0).getNumOfFiles();
		int minNumFiles = results.get(0).getNumOfFiles();
		float averageNumFiles = 0;
		//loop through every object (node) in the list
		for (int i=0;i<results.size();i++){
			
			//sum number of files per node
			averageNumFiles = averageNumFiles + results.get(i).getNumOfFiles();
			
			//get the maximum number of files on a given node
			if (maxNumFiles < results.get(i).getNumOfFiles())
				maxNumFiles = results.get(i).getNumOfFiles();
			//get the minimum number of files on a given node, probably zero always
			if(minNumFiles > results.get(i).getNumOfFiles())
				minNumFiles = results.get(i).getNumOfFiles();
								
		}
		averageNumFiles = averageNumFiles/results.size();
		out.println("<h3>Number of Files</h3>");
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println("<tr> <th>Min</th> <th>Max</th> <th>Avg</th> </tr>");
		out.println("<tr>");
		out.println("<td>" + minNumFiles + "</td>");
		out.println("<td>" + maxNumFiles + "</td>");
		out.println("<td>" + averageNumFiles + "</td>");
		out.println("</tr>");
		out.println("</table>");
	}
	
	
	public void printAvgMinMaxFileSizes() {
		
		int maxFileSize = 0, minFileSize = 0;
		float avgFileSize = 0;
		
		// Create an ArrayList of all the file sizes
		ArrayList<Integer> fileSizesAL = new ArrayList<Integer>(); 
		for(int i=0; i<results.size(); i++) {
			fileSizesAL.addAll( results.get(i).getFilesListSize() );
		}
		
		// Convert the ArrayList into an int[] and sort it
		Object[] fileSizeOA = fileSizesAL.toArray();
		int[] fileSizes = new int[fileSizeOA.length];
		for(int i=0; i<fileSizeOA.length; i++) {
			fileSizes[i] = Integer.parseInt(fileSizeOA[i].toString());
		}
		Arrays.sort(fileSizes);
		
		// Set min/max/avg values
		if (fileSizes.length > 0){
			minFileSize = fileSizes[0]; // min is the first element
			maxFileSize = fileSizes[fileSizes.length-1]; // max is the last element
		}
		for(int i=0; i<fileSizes.length; i++) {
			avgFileSize += fileSizes[i];
		}
		avgFileSize = avgFileSize/fileSizes.length;
		
		// Print results
		out.println("<h3>File Sizes</h3>");
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println("<tr> <th>Min</th> <th>Max</th> <th>Avg</th> </tr>");
		out.println("<tr>");
		out.println("<td>" + minFileSize + "</td>");
		out.println("<td>" + maxFileSize + "</td>");
		out.println("<td>" + avgFileSize + "</td>");
		out.println("</tr>");
		out.println("</table>");
	}
	
	public void printTop10Ext() {
		
		ArrayList<String> allExtensions = new ArrayList<String>();
		ArrayList<Integer> extCount = new ArrayList<Integer>();
		int foundflag = 0;
		
		//loop through every object (node) in the list
		for (int i = 0; i<results.size();i++){
			
			//loop through every filename and find if they have an extension 
			for (int j=0;j<results.get(i).getFilesList().size();j++){
				if (results.get(i).getFilesList().get(j).lastIndexOf('.')!= -1){//check that the file has an extension
					
					//for files with extensions, compare it against the known extensions
					//if already in list of allExtensions, add 1 to the count and sort
					for (int k = 0;k<allExtensions.size();k++){
						if(results.get(i).getFilesList().get(j).substring(results.get(i).getFilesList().get(j).lastIndexOf('.')).compareTo(allExtensions.get(k)) == 0)
						{
							extCount.set(k, extCount.get(k)+1);
							int s = k;
							if (s>0){ //Sort the lists according to count number
								while (extCount.get(s)> extCount.get(s-1)){
										allExtensions.add(s-1, allExtensions.get(s));
										allExtensions.remove(s+1);
										extCount.add(s-1,extCount.get(s));
										extCount.remove(s+1);
										s--;
										if (s == 0) break;
								}
							}
							foundflag = 1;
							break;
						}
					}
					//if not found to be a known extension, add it and initiate count
					if (foundflag == 0){
						allExtensions.add(results.get(i).getFilesList().get(j).substring(results.get(i).getFilesList().get(j).lastIndexOf('.')));
						extCount.add(1);
					}
					else foundflag = 0;
				}
			}
		}
		//Finally select the 10 extensions with highest count
		out.println("<h3>Top Ten Extensions</h3>");
		out.println("<table border='1' bordercolor=#FFFFFF bgcolor=#A9D0F5 style='border-collapse:collapse;font-size:13px'>");
		out.println("<tr> <th>Rank</th> <th>Extension</th> <th>Count</th> </tr>");
		for (int index=0;index<10&&index<allExtensions.size();index++){
			out.println("<tr>");
			out.println("<td>" + (index+1) + "</td>" + 
					    "<td>" + allExtensions.get(index) + "</td>" + 
					    "<td>" + extCount.get(index) + "</td>");
			out.println("</tr>");
		}
		out.println("</table>");
	}	
}
